﻿using System.Text;

namespace RuoVea.CodeGen.Util;
/// <summary>
/// 字符串助手类
/// </summary>
public static class StringHelper
{

    //
    // 摘要:
    //     忽略大小写的字符串相等比较，判断是否与任意一个待比较字符串相等
    //
    // 参数:
    //   value:
    //     字符串
    //
    //   strs:
    //     待比较字符串数组
    public static bool EqualIgnoreCase(this string? value, params string?[] strs)
    {
        foreach (string b in strs)
        {
            if (string.Equals(value, b, StringComparison.OrdinalIgnoreCase))
            {
                return true;
            }
        }

        return false;
    }

    //
    // 摘要:
    //     忽略大小写的字符串开始比较，判断是否与任意一个待比较字符串开始
    //
    // 参数:
    //   value:
    //     字符串
    //
    //   strs:
    //     待比较字符串数组
    public static bool StartsWithIgnoreCase(this string? value, params string?[] strs)
    {
        if (value == null || string.IsNullOrEmpty(value))
        {
            return false;
        }

        foreach (string value2 in strs)
        {
            if (!string.IsNullOrEmpty(value2) && value.StartsWith(value2, StringComparison.OrdinalIgnoreCase))
            {
                return true;
            }
        }

        return false;
    }

    //
    // 摘要:
    //     忽略大小写的字符串结束比较，判断是否以任意一个待比较字符串结束
    //
    // 参数:
    //   value:
    //     字符串
    //
    //   strs:
    //     待比较字符串数组
    public static bool EndsWithIgnoreCase(this string? value, params string?[] strs)
    {
        if (value == null || string.IsNullOrEmpty(value))
        {
            return false;
        }

        foreach (string text in strs)
        {
            if (text != null && value.EndsWith(text, StringComparison.OrdinalIgnoreCase))
            {
                return true;
            }
        }

        return false;
    }

    //
    // 摘要:
    //     拆分字符串成为整型数组，默认逗号分号分隔，无效时返回空数组
    //
    // 参数:
    //   value:
    //     字符串
    //
    //   separators:
    //     分组分隔符，默认逗号分号
    //
    // 言论：
    //     过滤空格、过滤无效、不过滤重复
    public static int[] SplitAsInt(this string? value, params string[] separators)
    {
        if (value == null || string.IsNullOrEmpty(value))
        {
            return Array.Empty<int>();
        }

        if (separators == null || separators.Length == 0)
        {
            separators = new string[2] { ",", ";" };
        }

        string[] array = value.Split(separators, StringSplitOptions.RemoveEmptyEntries);
        List<int> list = new List<int>();
        string[] array2 = array;
        for (int i = 0; i < array2.Length; i++)
        {
            if (int.TryParse(array2[i].Trim(), out var result))
            {
                list.Add(result);
            }
        }

        return list.ToArray();
    }

    //
    // 摘要:
    //     追加分隔符字符串，忽略开头，常用于拼接
    //
    // 参数:
    //   sb:
    //     字符串构造者
    //
    //   separator:
    //     分隔符
    public static StringBuilder Separate(this StringBuilder sb, string separator)
    {
        if (string.IsNullOrEmpty(separator))
        {
            return sb;
        }

        if (sb.Length > 0)
        {
            sb.Append(separator);
        }

        return sb;
    }

    //
    // 摘要:
    //     字符串转数组
    //
    // 参数:
    //   value:
    //     字符串
    //
    //   encoding:
    //     编码，默认utf-8无BOM
    public static byte[] GetBytes(this string? value, Encoding? encoding = null)
    {
        if (string.IsNullOrEmpty(value))
        {
            return Array.Empty<byte>();
        }

        if (encoding == null)
        {
            encoding = Encoding.UTF8;
        }

        return encoding.GetBytes(value);
    }


    //
    // 摘要:
    //     确保字符串以指定的另一字符串开始，不区分大小写
    //
    // 参数:
    //   str:
    //     字符串
    //
    //   start:
    public static string EnsureStart(this string? str, string start)
    {
        if (string.IsNullOrEmpty(start))
        {
            return str ?? "";
        }

        if (string.IsNullOrEmpty(str) || str == null)
        {
            return start ?? "";
        }

        if (str.StartsWith(start, StringComparison.OrdinalIgnoreCase))
        {
            return str;
        }

        return start + str;
    }

    //
    // 摘要:
    //     确保字符串以指定的另一字符串结束，不区分大小写
    //
    // 参数:
    //   str:
    //     字符串
    //
    //   end:
    public static string EnsureEnd(this string? str, string end)
    {
        if (string.IsNullOrEmpty(end))
        {
            return str ?? "";
        }

        if (string.IsNullOrEmpty(str) || str == null)
        {
            return end ?? "";
        }

        if (str.EndsWith(end, StringComparison.OrdinalIgnoreCase))
        {
            return str;
        }

        return str + end;
    }

    //
    // 摘要:
    //     从当前字符串开头移除另一字符串，不区分大小写，循环多次匹配前缀
    //
    // 参数:
    //   str:
    //     当前字符串
    //
    //   starts:
    //     另一字符串
    public static string TrimStart(this string str, params string[] starts)
    {
        if (string.IsNullOrEmpty(str))
        {
            return str;
        }

        if (starts == null || starts.Length == 0 || string.IsNullOrEmpty(starts[0]))
        {
            return str;
        }

        for (int i = 0; i < starts.Length; i++)
        {
            if (str.StartsWith(starts[i], StringComparison.OrdinalIgnoreCase))
            {
                string text = str;
                int length = starts[i].Length;
                str = text.Substring(length, text.Length - length);
                if (string.IsNullOrEmpty(str))
                {
                    break;
                }

                i = -1;
            }
        }

        return str;
    }

    //
    // 摘要:
    //     从当前字符串结尾移除另一字符串，不区分大小写，循环多次匹配后缀
    //
    // 参数:
    //   str:
    //     当前字符串
    //
    //   ends:
    //     另一字符串
    public static string TrimEnd(this string str, params string[] ends)
    {
        if (string.IsNullOrEmpty(str))
        {
            return str;
        }

        if (ends == null || ends.Length == 0 || string.IsNullOrEmpty(ends[0]))
        {
            return str;
        }

        for (int i = 0; i < ends.Length; i++)
        {
            if (str.EndsWith(ends[i], StringComparison.OrdinalIgnoreCase))
            {
                string text = str;
                int length = ends[i].Length;
                str = text.Substring(0, text.Length - length);
                if (string.IsNullOrEmpty(str))
                {
                    break;
                }

                i = -1;
            }
        }

        return str;
    }

    //
    // 摘要:
    //     根据最大长度截取字符串，并允许以指定空白填充末尾
    //
    // 参数:
    //   str:
    //     字符串
    //
    //   maxLength:
    //     截取后字符串的最大允许长度，包含后面填充
    //
    //   pad:
    //     需要填充在后面的字符串，比如几个圆点
    public static string Cut(this string str, int maxLength, string? pad = null)
    {
        if (string.IsNullOrEmpty(str) || maxLength <= 0 || str.Length < maxLength)
        {
            return str;
        }

        int num = maxLength;
        if (pad != null && !string.IsNullOrEmpty(pad))
        {
            num -= pad.Length;
        }

        if (num <= 0)
        {
            throw new ArgumentOutOfRangeException("maxLength");
        }

        return str.Substring(0, num) + pad;
    }


    //
    // 摘要:
    //     从当前字符串结尾移除另一字符串以及之后的部分
    //
    // 参数:
    //   str:
    //     当前字符串
    //
    //   ends:
    //     另一字符串
    public static string CutEnd(this string str, params string[] ends)
    {
        if (string.IsNullOrEmpty(str))
        {
            return str;
        }

        if (ends == null || ends.Length == 0 || string.IsNullOrEmpty(ends[0]))
        {
            return str;
        }

        for (int i = 0; i < ends.Length; i++)
        {
            int num = str.LastIndexOf(ends[i]);
            if (num >= 0)
            {
                str = str.Substring(0, num);
                if (string.IsNullOrEmpty(str))
                {
                    break;
                }
            }
        }

        return str;
    }

    //
    // 摘要:
    //     编辑距离
    //
    // 参数:
    //   str1:
    //
    //   str2:
    //
    // 言论：
    //     又称Levenshtein距离（也叫做Edit Distance），是指两个字串之间，由一个转成另一个所需的最少编辑操作次数。 许可的编辑操作包括将一个字符替换成另一个字符，插入一个字符，删除一个字符。
    //     算法代码由@Aimeast 独立完成。http://www.cnblogs.com/Aimeast/archive/2011/09/05/2167844.html
    public static int LevenshteinDistance(string str1, string str2)
    {
        int length = str1.Length;
        int length2 = str2.Length;
        int[,] array = new int[length + 1, length2 + 1];
        for (int i = 0; i <= length; i++)
        {
            array[i, 0] = i;
        }

        for (int i = 1; i <= length2; i++)
        {
            array[0, i] = i;
        }

        for (int i = 0; i < length; i++)
        {
            for (int j = 0; j < length2; j++)
            {
                int val = array[i, j + 1] + 1;
                int val2 = array[i + 1, j] + 1;
                array[i + 1, j + 1] = Math.Min(val2: str1[i] != str2[j] ? array[i, j] + 1 : array[i, j], val1: Math.Min(val, val2));
            }
        }

        return array[length, length2];
    }


    //
    // 摘要:
    //     最长公共子序列问题是寻找两个或多个已知数列最长的子序列。 一个数列 S，如果分别是两个或多个已知数列的子序列，且是所有符合此条件序列中最长的，则 S 称为已知序列的最长公共子序列。
    //     The longest common subsequence (LCS) problem is to find the longest subsequence
    //     common to all sequences in a set of sequences (often just two). Note that subsequence
    //     is different from a substring, see substring vs. subsequence. It is a classic
    //     computer science problem, the basis of diff (a file comparison program that outputs
    //     the differences between two files), and has applications in bioinformatics.
    //
    // 参数:
    //   word:
    //
    //   keys:
    //     多个关键字。长度必须大于0，必须按照字符串长度升序排列。
    //
    // 言论：
    //     算法代码由@Aimeast 独立完成。http://www.cnblogs.com/Aimeast/archive/2011/09/05/2167844.html
    public static int LCSDistance(string word, string[] keys)
    {
        int length = word.Length;
        int num = length;
        bool[] array = new bool[length];
        int[,] array2 = new int[length + 1, keys[^1].Length + 1];
        foreach (string text in keys)
        {
            int length2 = text.Length;
            int num2 = 0;
            int num3 = 0;
            int num4 = 0;
            int j = 0;
            for (num4 = 0; num4 < length; num4++)
            {
                for (j = 0; j < length2; j++)
                {
                    if (word[num4] == text[j])
                    {
                        array2[num4 + 1, j + 1] = array2[num4, j] + 1;
                        if (num2 < array2[num4, j])
                        {
                            num3 = num4;
                            num2 = array2[num4, j];
                        }
                    }
                    else
                    {
                        array2[num4 + 1, j + 1] = Math.Max(array2[num4, j + 1], array2[num4 + 1, j]);
                    }
                }
            }

            int num5 = array2[num4, j];
            if (num5 <= length2 >> 1)
            {
                return -1;
            }

            while (num4 > 0 && j > 0)
            {
                if (array2[num4 - 1, j - 1] + 1 == array2[num4, j])
                {
                    num4--;
                    j--;
                    if (!array[num4])
                    {
                        array[num4] = true;
                        num--;
                    }

                    num2 = num4;
                }
                else if (array2[num4 - 1, j] == array2[num4, j])
                {
                    num4--;
                }
                else
                {
                    j--;
                }
            }

            if (num5 <= num3 - num2 + 1 >> 1)
            {
                return -1;
            }
        }

        return num;
    }

    //
    // 摘要:
    //     模糊匹配
    //
    // 参数:
    //   str:
    //
    //   key:
    //
    //   maxError:
    public static KeyValuePair<int, int> Match(string str, string key, int maxError = 0)
    {
        int num = 0;
        int num2 = 0;
        int num3 = 0;
        int i;
        for (i = 0; i <= maxError; i++)
        {
            if (num2 >= key.Length)
            {
                break;
            }

            for (int j = num; j < str.Length; j++)
            {
                if (str[j] == key[num2])
                {
                    num2++;
                    num = j + 1;
                    num3++;
                    if (num2 == key.Length)
                    {
                        break;
                    }
                }
            }

            if (num2 == key.Length)
            {
                break;
            }

            num2++;
        }

        return new KeyValuePair<int, int>(num3, i);
    }

}
